﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows.Input;

namespace mediaPrime.Sdk
{
    public abstract class BasePlugin
    {
        internal static Action<BasePlugin> preInitialize = null;
        internal static bool initializing = false;

        public BasePlugin()
        {
            AvailableAddons = new ReadOnlyCollection<ExtensionInfo>(availableAddons);

            if (preInitialize != null)
                preInitialize(this);

            mediaPrime.Sdk.Settings.SettingChanged += Settings_SettingChanged;
        }

        /// <summary>
        /// The Plugin's unique id, specified in mediaPrime.Plugin.xml
        /// </summary>
        public string Id { get; internal set; }

        /// <summary>
        /// Path to the Plugin's directory
        /// </summary>
        public string Directory { get; internal set; }

        internal List<ExtensionInfo> availableAddons = new List<ExtensionInfo>();
        public ReadOnlyCollection<ExtensionInfo> AvailableAddons { get; set; }


        public AppSetting Settings { get; internal set; }
        public event SettingChangedEventHandler SettingChanged;


        private void Settings_SettingChanged(object sender, SettingChangedEventArgs e)
        {
            if (e.AppId == Id)
            {
                var settingChanged = SettingChanged;
                if (settingChanged != null)
                    settingChanged(this, e);
            }
        }

        public void GotToHome()
        {
            SendKeys.SendKey(Key.Escape);
        }


        #region Messaging

        internal event MessageWithResultEventHandler MessageWithResultSent;

        internal object SendMessageWithResult(string receiver, string type)
        {
            return SendMessageWithResult(receiver, type, null);
        }

        internal object SendMessageWithResult(string receiver, string type, object parameters)
        {
            var message = new Message();
            message.Sender = Id;
            message.Receiver = receiver;
            message.Content = new Query() { Type = type, Parameters = parameters };
            message.Type = MessageTypes.Query;

            var messageWithResultSent = MessageWithResultSent;

            if (messageWithResultSent != null)
                return messageWithResultSent(this, new MessageEventArgs(message));
            else
                return null;
        }


        /// <summary>
        /// Sends a message to another Plugin or to mediaPrime
        /// </summary>
        /// <param name="message">Message</param>
        public void SendMessage(Message message)
        {
            message.Sender = Id;

            Task.Run(() => onMessageSent(message));
        }

        /// <summary>
        /// Sends a message to mediaPrime
        /// </summary>
        /// <param name="content">Content</param>
        public void SendMessage(object content)
        {
            SendMessage(MessageReceivers.mediaPrime, content);
        }

        /// <summary>
        /// Sends a message to the specified receiver
        /// </summary>
        /// <param name="receiver">Receiver</param>
        /// <param name="content">Content</param>
        public void SendMessage(string receiver, object content)
        {
            var message = new Message();

            message.Content = content;
            message.Receiver = receiver;

            SendMessage(message);
        }

        /// <summary>
        /// Sends a notification to the user
        /// </summary>
        /// <param name="title">The title text of the notification</param>
        /// <param name="content">The content text of the notification</param>
        public void SendNotification(string title, string content)
        {
            var notification = new Notification();

            notification.Title = title;
            notification.Content = content;

            SendNotification(notification);
        }

        /// <summary>
        /// Sends a notification to the user
        /// </summary>
        /// <param name="title">The title text of the notification</param>
        /// <param name="content">The content text of the notification</param>
        /// <param name="date">The date of the notification</param>
        /// <param name="action">When the user clicked on the notification, this value can be used to handle further action</param>
        /// <param name="showPlugin">Defines whether this Plugin should be shown after the user clicked on the notification</param>
        public void SendNotification(string title, string content, DateTime date, string action, bool showPlugin)
        {
            var notification = new Notification();

            notification.Title = title;
            notification.Content = content;
            notification.Date = date;
            notification.Action = action;
            notification.ShowPlugin = showPlugin;

            SendNotification(notification);
        }

        /// <summary>
        /// Sends a notification to the user
        /// </summary>
        /// <param name="notification">Notifcation</param>
        public void SendNotification(Notification notification)
        {
            var message = new Message();

            message.Content = notification;
            message.Type = MessageTypes.Notification;

            SendMessage(message);
        }

        /// <summary>
        /// Sends a query to mediaPrime, the result will be available in the QueryResult event
        /// </summary>
        /// <param name="type">Query type</param>
        public void SendQuery(string type)
        {
            SendQuery(MessageReceivers.mediaPrime, type, null);
        }

        /// <summary>
        /// Sends a query to mediaPrime, the result will be available in the QueryResult event
        /// </summary>
        /// <param name="type">Query type</param>
        /// <param name="parameters">Additional parameters</param>
        public void SendQuery(string type, object parameters)
        {
            SendQuery(MessageReceivers.mediaPrime, type, parameters);
        }

        /// <summary>
        /// Sends a query to the specified receiver, the result will be available in the QueryResult event
        /// </summary>
        /// <param name="receiver">Receiver which handles this request</param>
        /// <param name="type">Query type</param>
        /// <param name="parameters">Additional paramters</param>
        public void SendQuery(string receiver, string type, object parameters)
        {
            var message = new Message();

            message.Receiver = receiver;
            message.Content = new Query() { Type = type, Parameters = parameters };
            message.Type = MessageTypes.Query;

            SendMessage(message);
        }

        public void SendQueryResult(string type, object result)
        {
            SendQueryResult(MessageReceivers.mediaPrime, type, result);
        }


        public void SendQueryResult(string receiver, string type, object result)
        {
            var message = new Message();

            message.Receiver = receiver;
            message.Content = new QueryResult() { Type = type, Result = result };
            message.Type = MessageTypes.QueryResult;

            SendMessage(message);
        }



        internal event MessageEventHandler MessageSent;
        private void onMessageSent(Message message)
        {
            var messageSent = MessageSent;

            if (messageSent != null)
                messageSent(this, new MessageEventArgs(message));

        }

        public event MessageEventHandler MessageReceived;

        internal void OnMessageReceived(Message message)
        {
            if (message.Type == MessageTypes.Query)
            {
                OnQueryRequest(message);
            }
            else if (message.Type == MessageTypes.QueryResult)
            {
                OnQueryResult(message);
            }
            else
            {
                var messageReceived = MessageReceived;
                if (messageReceived != null)
                    messageReceived(this, new MessageEventArgs(message));
            }
        }

        public event QueryRequestEventHandler QueryRequest;
        public event QueryResultEventHandler QueryResult;

        internal void OnQueryRequest(Message message)
        {
            var queryRequest = QueryRequest;
            if (queryRequest != null)
            {
                var query = message.Content as Query;
                if (query != null)
                    queryRequest(this, new QueryRequestEventArgs(message.Sender, query.Type, query.Parameters));
            }
        }

        internal void OnQueryResult(Message message)
        {
            var queryResult = QueryResult;
            if (queryResult != null)
            {
                var query = message.Content as QueryResult;
                if (query != null)
                    queryResult(this, new QueryResultEventArgs(message.Sender, query.Type, query.Result, query.Exception));
            }
        }

        public event CustomSettingDisplayNameRequestEventHandler CustomSettingDisplayNameRequest;
        public event CustomSettingDialogRequestEventHandler CustomSettingDialogRequest;

        internal object OnMessageWithResultReceived(Message message)
        {
            if (message.Content is Query)
            {
                var query = message.Content as Query;

                if (query.Type == QueryTypes.CustomSettingDisplayName)
                {
                    var customSettingDisplayNameRequest = CustomSettingDisplayNameRequest;
                    if (customSettingDisplayNameRequest != null)
                        return customSettingDisplayNameRequest(this, new SettingEventArgs(query.Parameters as Setting));
                }
                else if (query.Type == QueryTypes.CustomSettingsDialog)
                {
                    var customSettingDialogRequest = CustomSettingDialogRequest;
                    if (customSettingDialogRequest != null)
                        return customSettingDialogRequest(this, new SettingEventArgs(query.Parameters as Setting));
                }
            }

            return null;
        }

        #endregion





    }


}
